#include "HttpDownloader.h"

#include <QNetworkAccessManager>
#include <qfile.h>
#include <qfiledialog.h>
#include <qurl.h>
#include <qmessagebox.h>
#include <QNetworkRequest>
#include <QHttpMultiPart>
#include <QHttpPart>
#include <qvariant.h>
#include <qdatetime.h>

#define DEBUG_STATE 1

void HttpDownloader::on_pushButton_upload_clicked()
{
    InitProgressbar();
    SetWidgetState(WIDGET_STATE::UPLOADED_STATE);
    QString _str{ ui.lineEdit_upload_file->text().trimmed() };
    if (m_file)
    {
       
        m_file->setFileName(_str);
        if (!m_file->open(QIODevice::ReadOnly))
        {
            m_file->close();
            WriteLog(QString("%1 open file fail").arg(__FUNCTION__));
            return;
        }
        else
        {
            QString _upload_url{ ui.lineEdit_upload_url->text()};
            if (_upload_url.isEmpty())
            {
                QMessageBox::warning(this, "warning", "please input correct url!");
                return;
            }
            QNetworkRequest _request(_upload_url);
            QHttpMultiPart* _multi_part = new QHttpMultiPart(QHttpMultiPart::FormDataType);
            QHttpPart _part{};
            QString _data{ QString("form-data; name=\"files\";filename=\"%1\"").arg(GetFileName(_str)) };
            _part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(_data));
            _part.setBodyDevice(m_file);
            _multi_part->append(_part);
            m_reply = m_manager->post(_request, _multi_part);
            m_elapsed.start();
            Q_ASSERT(m_reply);
            _multi_part->setParent(m_reply);
            connect(m_reply, &QNetworkReply::readyRead, this, &HttpDownloader::OnUploadReadContent);
            connect(m_reply, &QNetworkReply::errorOccurred, this, &HttpDownloader::OnError);
            connect(m_reply, &QNetworkReply::uploadProgress, this, &HttpDownloader::OnProgress);
        }
    }
}

void HttpDownloader::on_pushButton_download_clicked()
{
    InitProgressbar();
    QString _download_url{ ui.lineEdit_download_url->text() };
    if (_download_url.isEmpty())
    {
        WriteLog("please input valid download url");
        return;
    }
    QString _download_filename{ ui.lineEdit_download_file->text() };
    if (_download_url.isEmpty())
    {
        WriteLog("please input valid download file");
        return;
    }
    QString _str{ ui.lineEdit_download_file->text().trimmed() };

    if (m_file)
    {
        m_file->setFileName(_str);
        if (!m_file->open(QIODevice::WriteOnly ))
        {
            WriteLog(QString("%1 open file fail").arg(__func__));
            m_file->close();
            return;
        }
       
        QString _url{ QString("%1?fileName=%2").arg(_download_url).arg(GetFileName( _download_filename)) };
        QNetworkRequest _request{ _url };
        WriteLog(QString("url:[%1]").arg(_url));
        m_reply = m_manager->get(_request);
        m_elapsed.restart();
        Q_ASSERT(m_reply);
        connect(m_reply, &QIODevice::readyRead, this, &HttpDownloader::OnDownloadData);
        connect(m_reply, &QNetworkReply::errorOccurred, this, &HttpDownloader::OnError);
        connect(m_reply, &QNetworkReply::downloadProgress, this, &HttpDownloader::OnDownloadProgress);
        SetWidgetState(WIDGET_STATE::DOWNLOADED_STATE);
    }

}

void HttpDownloader::on_toolButton_upload_clicked()
{
    QString _str{ QFileDialog::getOpenFileName(this,"open file",QApplication::applicationDirPath(),"*.*") };
    if (_str.isEmpty())
        return;
    ui.lineEdit_upload_file->setText(_str);
    SetWidgetState(WIDGET_STATE::UPLOADING_STATE);
}

void HttpDownloader::on_toolButton_download_clicked()
{
    QString _file_name{ GetFileName( ui.lineEdit_download_file->text()) };
    if (_file_name.isEmpty())
    {
        WriteLog("download file is empty");
        return;
    }
    ui.lineEdit_download_file->clear();
    QString _save_path{ QFileDialog::getExistingDirectory(this, "save path", QApplication::applicationDirPath()) };
    if (_save_path.isEmpty())
        return;
    QString _full_path{ QString("%1/%2").arg(_save_path,_file_name) };
    ui.lineEdit_download_file->setText(_full_path);
    SetWidgetState(WIDGET_STATE::DOWNLOADING_STATE);
}

void HttpDownloader::on_pushButton_cancel_clicked()
{

}

void HttpDownloader::OnFinished(QNetworkReply* )
{
    if (m_reply)
    {
        if (QNetworkReply::NoError == m_reply->error())
        {
            m_reply->deleteLater();
            m_file->flush();
            m_file->close();
            WriteLog("operate finished");
            auto _end = (double)m_elapsed.elapsed()/(double)1000;
            ui.label_elapsed->setText(QString::number(_end,'f',3));
        }
        else
        {
            QString _err{ QString("operate fail error:[%1]").arg(m_reply->errorString()) };
            WriteLog(_err);
        }
        SetWidgetState(WIDGET_STATE::STOPED_STATE);
    }
}



void HttpDownloader::OnUploadReadContent()
{
    if (m_reply)
    {
        QString _str{ m_reply->readAll().trimmed() };
        if (_str.isEmpty())
        {
            WriteLog("upload no response");
            return;
        }
        ui.lineEdit_download_file->setText(_str);
    }
}

void HttpDownloader::OnError(QNetworkReply::NetworkError code)
{
    if (m_reply)
    {
        QString _error{ QString("loading occur error:[%1],detail:[%2]").arg(code).arg(m_reply->errorString()) };
        WriteLog(_error);
        SetWidgetState(WIDGET_STATE::STOPED_STATE);
    }
}

void HttpDownloader::OnProgress(qint64 bytesSent, qint64 bytesTotal)
{
    QProgressBar* _ptr = ui.progressBar;
    if (_ptr)
    {
        if (0 != bytesTotal)
        {
            if (10'0000 < bytesTotal)
            {
                _ptr->setRange(0, bytesTotal / 1'0000);
                _ptr->setValue(bytesSent / 1'0000);
                SetCurBytes(bytesSent);
                ui.label_total_bytes->setText(QString("%1").arg(bytesTotal));
            }
            else
            {
                _ptr->setRange(0, bytesTotal);
                _ptr->setValue(bytesSent);
                ui.label_cur_bytes->setText(QString("%1").arg(bytesSent));
                ui.label_total_bytes->setText(QString("%1").arg(bytesTotal));
            }
            
        }
    }
}

void HttpDownloader::OnDownloadData()
{
    if (m_file && m_reply)
    {
        m_file->write(m_reply->readAll());
    }
}

void HttpDownloader::OnDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
    if (0 != bytesTotal)
    {
        qint64 _modify_bytes{};
        if (1'0000 < bytesTotal)
            _modify_bytes = bytesReceived / 1'0000;
        else
            _modify_bytes = bytesReceived;
        ui.progressBar->setRange(0, _modify_bytes);
        ui.progressBar->setValue(_modify_bytes);
        SetCurBytes(bytesReceived);
        ui.label_total_bytes->setText(QString::number(bytesTotal, 10));
    }
}

HttpDownloader::HttpDownloader(QWidget *parent)
    : QMainWindow(parent)
    , m_manager{}
    , m_file{}
    , m_reply{}
{
    ui.setupUi(this);
    OnInitDialog();
    connect(this, SIGNAL(signal_cur_bytes(qint64)), SLOT(SetCurBytes(qint64)));
}

void HttpDownloader::OnInitDialog()
{
    InitManager();
    InitFile();
    SetWidgetState(WIDGET_STATE::STOPED_STATE);
    InitProgressbar();
#if 0
    QString _str{ QString("%1/1676614466375-test.txt").arg(QApplication::applicationDirPath()) };
    QFile _file("H:/extern code/MyPro/qthttpmultipart/bin/x64/Debug/1676615662355-fuck.txt");
    if (!_file.open(QIODevice::WriteOnly))
    {
        _file.close();
    }
    _file.write("haha");
    _file.close();
    _file.setFileName(QString("%1/fuck.txt").arg(QApplication::applicationDirPath()));
    if (!_file.open(QIODevice::WriteOnly))
    {
        _file.close();
    }
    _file.write("haha");
    _file.close();
#endif // 0
}

void HttpDownloader::WriteLog(const QString& log)
{
    QPlainTextEdit* _ptr{ ui.plainTextEdit };
    if (_ptr)
    {
        int _row_cnt = _ptr->document()->blockCount();
        if (500 < _row_cnt)
            _ptr->clear();
        QString _log{ QString("[%1][%2] :%3")
            .arg(_row_cnt)
            .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"))
            .arg(log)};
        _ptr->appendPlainText(_log);
    }
}

void HttpDownloader::InitManager()
{
    if (nullptr == m_manager)
        m_manager = new QNetworkAccessManager(this);
    Q_ASSERT(m_manager);
    connect(m_manager, &QNetworkAccessManager::finished, this, &HttpDownloader::OnFinished);
}

void HttpDownloader::InitFile()
{
#if 1
    if (nullptr == m_file)
        m_file = new QFile(this);
    Q_ASSERT(m_file);
#endif // 0
}

void HttpDownloader::SetWidgetState(WIDGET_STATE state)
{
#if DEBUG_STATE
    m_widget_state = state;
    ui.toolButton_upload->setEnabled(WIDGET_STATE::STOPED_STATE == m_widget_state);
    ui.toolButton_download->setEnabled(WIDGET_STATE::STOPED_STATE == m_widget_state);
    ui.pushButton_upload->setEnabled(WIDGET_STATE::UPLOADING_STATE == m_widget_state);
    ui.pushButton_download->setEnabled(WIDGET_STATE::DOWNLOADING_STATE == m_widget_state);
    ui.pushButton_cancel->setEnabled(WIDGET_STATE::STARTED_STATE == m_widget_state);
#endif // DEBUG_STATE
}

void HttpDownloader::InitProgressbar()
{
    ui.progressBar->setValue(0);
    ui.label_cur_bytes->setText(QString::number(0));
    ui.label_total_bytes->setText(QString::number(0));
}

QString HttpDownloader::GetFileName(const QString&path)
{
    if (!path.isEmpty())
    {
        auto _index = path.lastIndexOf("/");
        QString _file_name = path.mid(_index+1);
        return _file_name;
    }
    else
    {
        WriteLog(QString("%1 file is empty").arg(__func__));
        return QString();
    }
}

void HttpDownloader::SetCurBytes(qint64 bytes)
{
    ui.label_cur_bytes->setText(QString::number(bytes));
}
